﻿/*
 * MIT License
 *Copyright (c) 2021 易开元(Easy-Open-Meta)

 *Permission is hereby granted, free of charge, to any person obtaining a copy
 *of this software and associated documentation files (the "Software"), to deal
 *in the Software without restriction, including without limitation the rights
 *to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *copies of the Software, and to permit persons to whom the Software is
 *furnished to do so, subject to the following conditions:

 *The above copyright notice and this permission notice shall be included in all
 *copies or substantial portions of the Software.

 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *SOFTWARE.
 *
 */
using EOM.TSHotelManagement.Common.Contract;
using EOM.TSHotelManagement.Common.Core;
using EOM.TSHotelManagement.Common.Util;
using EOM.TSHotelManagement.EntityFramework;
using EOM.TSHotelManagement.Shared;
using jvncorelib.EntityLib;
using SqlSugar;
using System.Security.Claims;

namespace EOM.TSHotelManagement.Application
{
    /// <summary>
    /// 员工信息接口实现类
    /// </summary>
    /// <remarks>
    /// 构造函数
    /// </remarks>
    /// <param name="workerRepository"></param>
    /// <param name="photoRepository"></param>
    /// <param name="educationRepository"></param>
    /// <param name="nationRepository"></param>
    /// <param name="deptRepository"></param>
    /// <param name="positionRepository"></param>
    /// <param name="passportTypeRepository"></param>
    /// <param name="jWTHelper"></param>
    /// <param name="mailHelper"></param>
    public class EmployeeService(GenericRepository<Employee> workerRepository, GenericRepository<EmployeePhoto> photoRepository, GenericRepository<Education> educationRepository, GenericRepository<Nation> nationRepository, GenericRepository<Department> deptRepository, GenericRepository<Position> positionRepository, GenericRepository<PassportType> passportTypeRepository, JWTHelper jWTHelper, MailHelper mailHelper, DataProtectionHelper dataProtectionHelper) : IEmployeeService
    {
        /// <summary>
        /// 员工信息
        /// </summary>
        private readonly GenericRepository<Employee> workerRepository = workerRepository;

        /// <summary>
        /// 员工照片
        /// </summary>
        private readonly GenericRepository<EmployeePhoto> photoRepository = photoRepository;

        /// <summary>
        /// 学历类型
        /// </summary>
        private readonly GenericRepository<Education> educationRepository = educationRepository;

        /// <summary>
        /// 民族类型
        /// </summary>
        private readonly GenericRepository<Nation> nationRepository = nationRepository;

        /// <summary>
        /// 部门
        /// </summary>
        private readonly GenericRepository<Department> deptRepository = deptRepository;

        /// <summary>
        /// 职务
        /// </summary>
        private readonly GenericRepository<Position> positionRepository = positionRepository;

        /// <summary>
        /// 证件
        /// </summary>
        private readonly GenericRepository<PassportType> passportTypeRepository = passportTypeRepository;

        /// <summary>
        /// 数据保护
        /// </summary>
        private readonly DataProtectionHelper dataProtector = dataProtectionHelper;

        /// <summary>
        /// JWT加密
        /// </summary>
        private readonly JWTHelper jWTHelper = jWTHelper;

        /// <summary>
        /// 邮件助手
        /// </summary>
        private readonly MailHelper mailHelper = mailHelper;

        /// <summary>
        /// 修改员工信息
        /// </summary>
        /// <param name="updateEmployeeInputDto"></param>
        /// <returns></returns>
        public BaseResponse UpdateEmployee(UpdateEmployeeInputDto updateEmployeeInputDto)
        {
            try
            {
                //加密联系方式
                var sourceTelStr = string.Empty;
                if (!updateEmployeeInputDto.PhoneNumber.IsNullOrEmpty())
                {
                    sourceTelStr = dataProtector.EncryptEmployeeData(updateEmployeeInputDto.PhoneNumber);
                }
                //加密身份证
                var sourceIdStr = string.Empty;
                if (!updateEmployeeInputDto.IdCardNumber.IsNullOrEmpty())
                {
                    sourceIdStr = dataProtector.EncryptEmployeeData(updateEmployeeInputDto.IdCardNumber);
                }
                updateEmployeeInputDto.PhoneNumber = sourceTelStr;
                updateEmployeeInputDto.IdCardNumber = sourceIdStr;

                var password = workerRepository.GetFirst(a => a.EmployeeId == updateEmployeeInputDto.EmployeeId).Password;
                updateEmployeeInputDto.Password = password;

                workerRepository.Update(EntityMapper.Map<UpdateEmployeeInputDto, Employee>(updateEmployeeInputDto));
            }
            catch (Exception ex)
            {
                return new BaseResponse { Message = LocalizationHelper.GetLocalizedString(ex.Message, ex.Message), Code = BusinessStatusCode.InternalServerError };
            }
            return new BaseResponse();

        }

        /// <summary>
        /// 员工账号禁/启用
        /// </summary>
        /// <param name="updateEmployeeInputDto"></param>
        /// <returns></returns>
        public BaseResponse ManagerEmployeeAccount(UpdateEmployeeInputDto updateEmployeeInputDto)
        {
            try
            {
                workerRepository.Update(a => new Employee()
                {
                    IsEnable = updateEmployeeInputDto.IsEnable,
                }, a => a.EmployeeId == updateEmployeeInputDto.EmployeeId);
            }
            catch (Exception ex)
            {
                return new BaseResponse { Message = LocalizationHelper.GetLocalizedString(ex.Message, ex.Message), Code = BusinessStatusCode.InternalServerError };
            }
            return new BaseResponse();
        }

        /// <summary>
        /// 添加员工信息
        /// </summary>
        /// <param name="createEmployeeInputDto"></param>
        /// <returns></returns>
        public BaseResponse AddEmployee(CreateEmployeeInputDto createEmployeeInputDto)
        {
            try
            {
                //加密联系方式
                var sourceTelStr = string.Empty;
                if (!createEmployeeInputDto.PhoneNumber.IsNullOrEmpty())
                {
                    sourceTelStr = dataProtector.EncryptEmployeeData(createEmployeeInputDto.PhoneNumber);
                }
                //加密身份证
                var sourceIdStr = string.Empty;
                if (!createEmployeeInputDto.IdCardNumber.IsNullOrEmpty())
                {
                    sourceIdStr = dataProtector.EncryptEmployeeData(createEmployeeInputDto.IdCardNumber);
                }
                // 加密密码
                var sourcePwdStr = string.Empty;
                var newPassword = new RandomStringGenerator().GenerateSecurePassword();
                sourcePwdStr = dataProtector.EncryptEmployeeData(newPassword);

                var emailTemplate = EmailTemplate.GetNewRegistrationTemplate(newPassword);
                var result = mailHelper.SendMail(new List<string> { createEmployeeInputDto.EmailAddress }, emailTemplate.Subject, emailTemplate.Body, new List<string> { createEmployeeInputDto.EmailAddress });
                if (!result)
                {
                    return new BaseResponse { Message = LocalizationHelper.GetLocalizedString("E-Mail Config Invaild, Add Employee Faild", "电子邮件配置无效，添加员工失败"), Code = BusinessStatusCode.InternalServerError };
                }

                createEmployeeInputDto.PhoneNumber = sourceTelStr;
                createEmployeeInputDto.IdCardNumber = sourceIdStr;
                createEmployeeInputDto.Password = sourcePwdStr;

                workerRepository.Insert(EntityMapper.Map<CreateEmployeeInputDto, Employee>(createEmployeeInputDto));

            }
            catch (Exception ex)
            {
                return new BaseResponse { Message = LocalizationHelper.GetLocalizedString(ex.Message, ex.Message), Code = BusinessStatusCode.InternalServerError };
            }
            return new BaseResponse();
        }

        /// <summary>
        /// 获取所有工作人员信息
        /// </summary>
        /// <returns></returns>
        public ListOutputDto<ReadEmployeeOutputDto> SelectEmployeeAll(ReadEmployeeInputDto readEmployeeInputDto)
        {
            var where = Expressionable.Create<Employee>();

            where = where.And(a => a.IsDelete != 1);

            //查询所有教育程度信息
            List<Education> educations = new List<Education>();
            educations = educationRepository.GetList(a => a.IsDelete != 1);
            //查询所有性别类型信息
            var helper = new EnumHelper();
            var genders = Enum.GetValues(typeof(GenderType))
                .Cast<GenderType>()
                .Select(e => new EnumDto
                {
                    Id = (int)e,
                    Name = e.ToString(),
                    Description = helper.GetEnumDescription(e)
                })
                .ToList();
            //查询所有民族类型信息
            List<Nation> nations = new List<Nation>();
            nations = nationRepository.GetList(a => a.IsDelete != 1);
            //查询所有部门信息
            List<Department> depts = new List<Department>();
            depts = deptRepository.GetList(a => a.IsDelete != 1);
            //查询所有职位信息
            List<Position> positions = new List<Position>();
            positions = positionRepository.GetList(a => a.IsDelete != 1);
            //查询所有证件类型
            List<PassportType> passportTypes = new List<PassportType>();
            passportTypes = passportTypeRepository.GetList(a => a.IsDelete != 1);
            //查询所有员工信息
            List<Employee> employees = new List<Employee>();

            var count = 0;

            if (!readEmployeeInputDto.IgnorePaging && readEmployeeInputDto.Page != 0 && readEmployeeInputDto.PageSize != 0)
            {
                employees = workerRepository.AsQueryable().Where(where.ToExpression())
                    .OrderBy(a => a.EmployeeId)
                    .ToPageList(readEmployeeInputDto.Page, readEmployeeInputDto.PageSize, ref count);
            }
            else
            {
                employees = workerRepository.AsQueryable().Where(where.ToExpression())
                    .OrderBy(a => a.EmployeeId)
                    .ToList();
                count = employees.Count;
            }

            employees.ForEach(source =>
            {
                //解密身份证号码
                var sourceStr = dataProtector.DecryptEmployeeData(source.IdCardNumber);
                source.IdCardNumber = sourceStr;
                //解密联系方式
                var sourceTelStr = dataProtector.DecryptEmployeeData(source.PhoneNumber);
                source.PhoneNumber = sourceTelStr;
                //性别类型
                var sexType = genders.SingleOrDefault(a => a.Id == source.Gender);
                source.GenderName = sexType.IsNullOrEmpty() ? "" : sexType.Description;
                //教育程度
                var eduction = educations.SingleOrDefault(a => a.EducationNumber == source.EducationLevel);
                source.EducationLevelName = eduction.IsNullOrEmpty() ? "" : eduction.EducationName;
                //民族类型
                var nation = nations.SingleOrDefault(a => a.NationNumber == source.Ethnicity);
                source.EthnicityName = nation.IsNullOrEmpty() ? "" : nation.NationName;
                //部门
                var dept = depts.SingleOrDefault(a => a.DepartmentNumber == source.Department);
                source.DepartmentName = dept.IsNullOrEmpty() ? "" : dept.DepartmentName;
                //职位
                var position = positions.SingleOrDefault(a => a.PositionNumber == source.Position);
                source.PositionName = position.IsNullOrEmpty() ? "" : position.PositionName;
                var passport = passportTypes.SingleOrDefault(a => a.PassportId == source.IdCardType);
                source.IdCardTypeName = passport.IsNullOrEmpty() ? "" : passport.PassportName;
                //面貌
                source.PoliticalAffiliationName = new EnumHelper().GetDescriptionByName<PoliticalAffiliation>(source.PoliticalAffiliation);
            });

            var Data = EntityMapper.MapList<Employee, ReadEmployeeOutputDto>(employees);

            return new ListOutputDto<ReadEmployeeOutputDto>
            {
                Data = new PagedData<ReadEmployeeOutputDto>
                {
                    Items = Data,
                    TotalCount = count
                }
            };
        }

        /// <summary>
        /// 根据登录名称查询员工信息
        /// </summary>
        /// <param name="readEmployeeInputDto"></param>
        /// <returns></returns>
        public SingleOutputDto<ReadEmployeeOutputDto> SelectEmployeeInfoByEmployeeId(ReadEmployeeInputDto readEmployeeInputDto)
        {
            Employee w = new Employee();
            var helper = new EnumHelper();
            var genders = Enum.GetValues(typeof(GenderType))
                .Cast<GenderType>()
                .Select(e => new EnumDto
                {
                    Id = (int)e,
                    Name = e.ToString(),
                    Description = helper.GetEnumDescription(e)
                })
                .ToList();
            w = workerRepository.GetFirst(a => a.EmployeeId == readEmployeeInputDto.EmployeeId);
            //解密身份证号码
            var sourceStr = w.IdCardNumber.IsNullOrEmpty() ? "" : dataProtector.DecryptEmployeeData(w.IdCardNumber);
            w.IdCardNumber = sourceStr;
            //解密联系方式
            var sourceTelStr = w.PhoneNumber.IsNullOrEmpty() ? "" : dataProtector.DecryptEmployeeData(w.PhoneNumber);
            w.PhoneNumber = sourceTelStr;
            //性别类型
            var sexType = genders.SingleOrDefault(a => a.Id == w.Gender);
            w.GenderName = sexType.Description.IsNullOrEmpty() ? "" : sexType.Description;
            //教育程度
            var eduction = educationRepository.GetFirst(a => a.EducationNumber == w.EducationLevel);
            w.EducationLevelName = eduction.EducationName.IsNullOrEmpty() ? "" : eduction.EducationName;
            //民族类型
            var nation = nationRepository.GetFirst(a => a.NationNumber == w.Ethnicity);
            w.EthnicityName = nation.NationName.IsNullOrEmpty() ? "" : nation.NationName;
            //部门
            var dept = deptRepository.GetFirst(a => a.DepartmentNumber == w.Department);
            w.DepartmentName = dept.DepartmentName.IsNullOrEmpty() ? "" : dept.DepartmentName;
            //职位
            var position = positionRepository.GetFirst(a => a.PositionNumber == w.Position);
            w.PositionName = position.PositionName.IsNullOrEmpty() ? "" : position.PositionName;
            var passport = passportTypeRepository.GetFirst(a => a.PassportId == w.IdCardType);
            w.IdCardTypeName = passport.IsNullOrEmpty() ? "" : passport.PassportName;
            //面貌
            w.PoliticalAffiliationName = new EnumHelper().GetDescriptionByName<PoliticalAffiliation>(w.PoliticalAffiliation);

            var source = EntityMapper.Map<Employee, ReadEmployeeOutputDto>(w);

            var employeePhoto = photoRepository.GetFirst(a => a.EmployeeId.Equals(source.EmployeeId));
            if (employeePhoto != null && !string.IsNullOrEmpty(employeePhoto.PhotoPath))
                source.PhotoUrl = employeePhoto.PhotoPath ?? string.Empty;

            return new SingleOutputDto<ReadEmployeeOutputDto> { Data = source };
        }

        /// <summary>
        /// 根据登录名称、密码查询员工信息
        /// </summary>
        /// <param name="readEmployeeInputDto"></param>
        /// <returns></returns>
        public SingleOutputDto<ReadEmployeeOutputDto> SelectEmployeeInfoByEmployeeIdAndEmployeePwd(ReadEmployeeInputDto readEmployeeInputDto)
        {
            Employee w = new Employee();
            var helper = new EnumHelper();
            var genders = Enum.GetValues(typeof(GenderType))
                .Cast<GenderType>()
                .Select(e => new EnumDto
                {
                    Id = (int)e,
                    Name = e.ToString(),
                    Description = helper.GetEnumDescription(e)
                })
                .ToList();
            w = workerRepository.GetFirst(a => a.EmployeeId == readEmployeeInputDto.EmployeeId || a.EmailAddress == readEmployeeInputDto.EmailAddress);
            if (w == null)
            {
                w = null;
                return new SingleOutputDto<ReadEmployeeOutputDto> { Data = null, Message = LocalizationHelper.GetLocalizedString("Employee does not exist or entered incorrectly", "员工不存在或输入有误") };
            }
            var dbPwd = string.Empty;

            dbPwd = dataProtector.DecryptEmployeeData(w.Password);

            if (dbPwd != readEmployeeInputDto.Password)
            {
                w = null;
                return new SingleOutputDto<ReadEmployeeOutputDto> { Data = EntityMapper.Map<Employee, ReadEmployeeOutputDto>(w) };
            }
            w.Password = "";
            //性别类型
            var sexType = genders.SingleOrDefault(a => a.Id == w.Gender);
            w.GenderName = sexType.Description.IsNullOrEmpty() ? "" : sexType.Description;
            //教育程度
            var eduction = educationRepository.GetFirst(a => a.EducationNumber == w.EducationLevel);
            w.EducationLevelName = eduction.EducationName.IsNullOrEmpty() ? "" : eduction.EducationName;
            //民族类型
            var nation = nationRepository.GetFirst(a => a.NationNumber == w.Ethnicity);
            w.EthnicityName = nation.NationName.IsNullOrEmpty() ? "" : nation.NationName;
            //部门
            var dept = deptRepository.GetFirst(a => a.DepartmentNumber == w.Department);
            w.DepartmentName = dept.DepartmentName.IsNullOrEmpty() ? "" : dept.DepartmentName;
            //职位
            var position = positionRepository.GetFirst(a => a.PositionNumber == w.Position);
            w.PositionName = position.PositionName.IsNullOrEmpty() ? "" : position.PositionName;

            w.UserToken = jWTHelper.GenerateJWT(new ClaimsIdentity(new List<Claim> { new Claim(ClaimTypes.Name, w.EmployeeName), new Claim(ClaimTypes.SerialNumber, w.EmployeeId) }));

            return new SingleOutputDto<ReadEmployeeOutputDto> { Data = EntityMapper.Map<Employee, ReadEmployeeOutputDto>(w) };
        }

        /// <summary>
        /// 修改员工账号密码
        /// </summary>
        /// <param name="updateEmployeeInputDto"></param>
        /// <returns></returns>
        public BaseResponse UpdateEmployeeAccountPassword(UpdateEmployeeInputDto updateEmployeeInputDto)
        {
            try
            {
                var employee = workerRepository.GetFirst(a => a.EmployeeId == updateEmployeeInputDto.EmployeeId);

                if (employee.IsNullOrEmpty())
                {
                    return new BaseResponse()
                    {
                        Message = LocalizationHelper.GetLocalizedString("This employee does not exists", "员工不存在"),
                        Code = BusinessStatusCode.InternalServerError
                    };
                }

                var currentPassword = dataProtector.DecryptEmployeeData(employee.Password);

                if (!updateEmployeeInputDto.OldPassword.Equals(currentPassword))
                {
                    return new BaseResponse()
                    {
                        Message = LocalizationHelper.GetLocalizedString("The old password is incorrect", "旧密码不正确"),
                        Code = BusinessStatusCode.InternalServerError
                    };
                }

                if (updateEmployeeInputDto.Password.Equals(currentPassword))
                {
                    return new BaseResponse()
                    {
                        Message = LocalizationHelper.GetLocalizedString("The new password cannot be the same as the old password", "新密码不能与旧密码相同"),
                        Code = BusinessStatusCode.InternalServerError
                    };
                }

                var newPwd = updateEmployeeInputDto.Password;
                string encrypted = dataProtector.EncryptEmployeeData(newPwd);

                if (!employee.EmailAddress.IsNullOrEmpty())
                {
                    var mailTemplate = EmailTemplate.GetUpdatePasswordTemplate(newPwd);
                    mailHelper.SendMail(new List<string> { employee.EmailAddress }, mailTemplate.Subject, mailTemplate.Body, new List<string> { employee.EmailAddress });
                }

                workerRepository.Update(new Employee()
                {
                    Id = employee.Id,
                    EmployeeId = employee.EmployeeId,
                    Password = encrypted,
                    IsInitialize = 1,
                    DataChgUsr = updateEmployeeInputDto.DataChgUsr,
                    DataChgDate = updateEmployeeInputDto.DataChgDate
                });
            }
            catch (Exception ex)
            {
                return new BaseResponse { Message = LocalizationHelper.GetLocalizedString(ex.Message, ex.Message), Code = BusinessStatusCode.InternalServerError };
            }

            return new BaseResponse();
        }

        /// <summary>
        /// 重置员工账号密码
        /// </summary>
        /// <param name="updateEmployeeInputDto"></param>
        /// <returns></returns>
        public BaseResponse ResetEmployeeAccountPassword(UpdateEmployeeInputDto updateEmployeeInputDto)
        {
            try
            {
                var newPwd = new RandomStringGenerator().GenerateSecurePassword();
                string encrypted = dataProtector.EncryptEmployeeData(newPwd);

                var employee = workerRepository.GetFirst(a => a.EmployeeId == updateEmployeeInputDto.EmployeeId);

                var emailAddress = employee.EmailAddress;

                if (emailAddress.IsNullOrEmpty())
                {
                    return new BaseResponse()
                    {
                        Message = LocalizationHelper.GetLocalizedString("No bound email address was found for the employee. Password reset cannot be completed."
                        , "未找到员工绑定的电子邮箱，无法重置密码。"),
                        Code = BusinessStatusCode.InternalServerError
                    };
                }

                var mailTemplate = EmailTemplate.GetResetPasswordTemplate(newPwd);

                var result = mailHelper.SendMail(new List<string> { emailAddress },
                    mailTemplate.Subject, mailTemplate.Body,
                    new List<string> { emailAddress });
                if (!result)
                {
                    return new BaseResponse { Message = LocalizationHelper.GetLocalizedString("E-Mail Config Invaild, Reset Password Faild", "电子邮件配置无效，重置密码失败"), Code = BusinessStatusCode.InternalServerError };
                }

                workerRepository.Update(new Employee()
                {
                    Id = employee.Id,
                    EmployeeId = employee.EmployeeId,
                    Password = encrypted,
                    DataChgUsr = updateEmployeeInputDto.DataChgUsr,
                    DataChgDate = updateEmployeeInputDto.DataChgDate
                });
            }
            catch (Exception ex)
            {
                return new BaseResponse { Message = LocalizationHelper.GetLocalizedString(ex.Message, ex.Message), Code = BusinessStatusCode.InternalServerError };
            }

            return new BaseResponse();
        }
    }
}
